package im.composer.media.sound.stream;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import javax.sound.sampled.AudioFormat;

import im.composer.audio.engine.Out;

import org.jaudiolibs.audioservers.AudioConfiguration;
import org.kc7bfi.jflac.FLACDecoder;
import org.kc7bfi.jflac.PCMProcessor;
import org.kc7bfi.jflac.metadata.StreamInfo;
import org.kc7bfi.jflac.util.ByteData;
import org.tritonus.share.sampled.FloatSampleTools;

public class FlacAudioIn extends Out implements PCMProcessor {

	private BlockingQueue<float[]> queue = new LinkedBlockingQueue<>();
	private final FLACDecoder decoder;
	private AudioFormat format = null;

	public FlacAudioIn(InputStream in, AudioConfiguration context) {
		super(context);
		decoder = new FLACDecoder(in);
		decoder.addPCMProcessor(this);
	}

	public void decode() throws IOException {
		decoder.decode();
	}

	@Override
	public void processStreamInfo(StreamInfo streamInfo) {
		format = streamInfo.getAudioFormat();
	}

	@Override
	public void processPCM(ByteData pcm) {
		if (format == null) {
			return;
		}
		byte[] bin = pcm.getData();
		int chan = getContext().getOutputChannelCount();
		List<float[]> list = new ArrayList<float[]>(chan);
		for (int i = 0; i < chan; i++) {
			list.add(new float[bufferSize]);
		}
		FloatSampleTools.byte2float(bin, 0, list, 0, bufferSize, format);
		for (int i = 0; i < bufferSize; i++) {
			float[] f = new float[chan];
			for (int j = 0; j < chan; j++) {
				f[j] = list.get(j)[i];
			}
			queue.offer(f);
		}
	}

	@Override
	protected void computeBuffer() {
		buf.makeSilence();
		for (int i = 0; i < bufferSize; i++) {
			float[] frame;
			frame = queue.poll();
			if (frame == null) {
				break;// jitter
			}
			// frame = queue.take();//blocking
			for (int j = 0; j < buf.getChannelCount(); j++) {
				buf.getChannel(j)[i] = frame[j];
			}
		}
	}

}
